package com.gitee.srurl.system.biz;

import cn.hutool.core.util.StrUtil;
import com.gitee.srurl.core.cache.ShortUrlVisitTimeCache;
import com.gitee.srurl.core.cache.record.ShortUrlCacheManager;
import com.gitee.srurl.core.constant.RedisConstant;
import com.gitee.srurl.core.dto.request.GenerateShortUrlDTO;
import com.gitee.srurl.core.dto.result.ShortUrlResultDTO;
import com.gitee.srurl.core.enums.ResponseCodeEnums;
import com.gitee.srurl.core.exception.ServiceException;
import com.gitee.srurl.core.factory.handle.GenerateShortUrlContext;
import com.gitee.srurl.core.util.MurmurHashUtil;
import com.gitee.srurl.core.util.RedisCacheUtil;
import com.gitee.srurl.core.util.ShortUrlUtil;
import com.gitee.srurl.core.util.login.OperationUser;
import com.gitee.srurl.core.util.redis.RedisLockUtil;
import com.gitee.srurl.system.exception.ShortUrlGenerateException;
import com.gitee.srurl.system.params.GenerateShortUrlParams;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.util.Optional;

/**
 * @author zxw
 * @date 2023/4/29 7:09
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class OpenApiBiz {

    private final GenerateShortUrlContext generateShortUrlContext;

    private final ShortUrlCacheManager shortUrlCacheManager;

    public ShortUrlResultDTO getShortUrl(GenerateShortUrlParams generateShortUrlParams) {

        String url = generateShortUrlParams.getUrl();
        if (StrUtil.isBlank(url)) {
            throw new ServiceException("待生成URL不能为空！");
        }

        GenerateShortUrlDTO generateShortUrlDTO = GenerateShortUrlDTO.builder()
                .originUrl(StrUtil.replace(url, " ", ""))
                .times(generateShortUrlParams.getTimes())
                .expireTime(generateShortUrlParams.getExpireTime())
                .updateTimes(generateShortUrlParams.getUpdateTimes())
                .build();
        // 如果获取失败 说明在执行中 这个取决于并发 32位的数量用在这应该是够了 不够的话可以改成128位
        final String lockKey = RedisConstant.Lock.ID_GEN_LOCK + MurmurHashUtil.murmur32(generateShortUrlParams.getUrl());
        ShortUrlResultDTO resultDTO;
        boolean lock = RedisLockUtil.tryLock(lockKey);
        try {
            if (!lock) {
                throw new ServiceException("该url请求执行中，请勿短时间内多次请求");
            }
            resultDTO = generateShortUrlContext.handle(generateShortUrlDTO);
            boolean success = Optional.ofNullable(resultDTO.getSuccess()).orElse(false);
            if (!success) {
                String errorMsg = resultDTO.getErrorMsg();
                errorMsg = StrUtil.isBlank(errorMsg) ? ResponseCodeEnums.SHORT_URL_GENERATE_FAIL.message() : errorMsg;
                throw new ShortUrlGenerateException(errorMsg);
            } else {
                // 只有设置了不允许每次更新都是新url 既 DuplicateDetectionHandle 那边才会设置这个参数
                if (resultDTO.getDisabled() != null && resultDTO.getDisabled()) {
                    // 说明被禁用 不允许更新
                    throw new ShortUrlGenerateException(ResponseCodeEnums.SHORT_URL_DISABLED);
                }
                // 设置redis 访问次数缓存
                String shortId = ShortUrlUtil.getShortIdByShortUrl(resultDTO.getShortUrl());
                // 查询历史数据是不是永久访问的
                ShortUrlResultDTO shortUrlResultDTO = this.peggingOriginUrlByShortId(shortId);
                // 历史是否是永久的访问次数
                boolean isInfinite = shortUrlResultDTO != null && Optional.ofNullable(shortUrlResultDTO.getTimes()).orElse(0L) == -1;
                if (resultDTO.getTimes() == -1) {
                    if (!isInfinite) {
                        boolean removed = ShortUrlVisitTimeCache.removeTimes(shortId);
                        if (!removed) {
                            log.error("短链ID:{},更新为永久链接参数 移除次数缓存失败", shortId);
                        }
                    }
                } else {
                    ShortUrlVisitTimeCache.setTimes(shortId, resultDTO.getTimes());
                }

                // 再次移除缓存
                RedisCacheUtil.removeCache(shortId, true);
                return resultDTO;
            }
        } finally {
            if (lock) {
                boolean unlock = RedisLockUtil.unlock(lockKey);
                if (!unlock) {
                    log.error("请求url:{},redis lock:{},释放失败", generateShortUrlParams.getUrl(), lockKey);
                }
            }
        }
    }

    public ShortUrlResultDTO peggingOriginUrl(String shortUrl, OperationUser loginUser) {

        ShortUrlResultDTO shortUrlResultDTO = this.peggingOriginUrlByShortId(ShortUrlUtil.getShortIdByShortUrl(shortUrl));
        if (shortUrlResultDTO == null) {
            return null;
        }
        if (!loginUser.getUserId().equals(shortUrlResultDTO.getCreateId())) {
            log.info("用户ID:{},不具备查询shortUrl:{},的权限", loginUser.getUserId(), shortUrlResultDTO);
            return null;
        }

        return shortUrlResultDTO;
    }

    public ShortUrlResultDTO peggingOriginUrlByShortId(String shortId) {

        if (StrUtil.isBlank(shortId)) {
            return null;
        }
        return shortUrlCacheManager.getCache(shortId);
    }
}
